#ifndef __CXX_GRPH_FONT_CACHE_H__
#define __CXX_GRPH_FONT_CACHE_H__

#include "grphoal.h"
#include "std/avltree.h"

namespace agg
{

	enum glyph_rendering
	{
		glyph_ren_native_mono,
		glyph_ren_native_gray8,
		glyph_ren_outline,
		glyph_ren_agg_mono,
		glyph_ren_agg_gray8
	};

	enum glyph_data_type
	{
		glyph_data_invalid = 0,
		glyph_data_mono    = 1,
		glyph_data_gray8   = 2,
		glyph_data_outline = 3
	};

	struct glyph_cache;

};	// end of namespace agg

namespace grphfntcache
{

using namespace visgrph;
using namespace grphoal;

// the fontcache magic number
const static unsigned int fntcache_magic1 = 'FntC';
const static unsigned int fntcache_magic2 = 'ache';

// we use at most 32MB font cache
const static unsigned int cachebuf_total_size = 32 * 1024 * 1024;

// normal font cache block size (16KB)
const static unsigned int cachebuf_block_size = 16 * 1024;

// font descriptor name storage space size
const static unsigned int cachebuf_font_desc_string_storage_size = 32 * 1024;

// max font faces supported
const static unsigned int max_font_faces = 512;

struct font_descriptor
{
	avl_node_t avlnode;
	avl_node_t* lru_tree;
	avl_node_t* fcache_tree;
	grphoal::uint128_t fid;
};

struct free_font_desc
{
	free_font_desc* next;
};

struct fcache_block_desc
{
	unsigned int freesize;
	fcache_block_desc* next;
	unsigned char buffer[4];
};

struct fcache
{
	unsigned int freesize;
	fcache_block_desc* next;
	// the members above shall not changed

	fcache_block_desc* curr_block;
	avl_node_t avlnode;
	avl_node_t* glyphs;
	unsigned int fontsize;

	unsigned char buffer[4];
};

union fcache_block
{
	fcache font_cache;
	fcache_block_desc font_block;
	unsigned char raw_data[cachebuf_block_size];
};

struct fontcache
{
	// magic
	unsigned int fontcache_magic1;
	unsigned int fontcache_magic2;

	// magic3 is the start address of fontcache
	// this is to check if the fontcache static data
	// being mapped to a same address in every process
	unsigned int fontcache_magic3;

	// free font descriptor list
	free_font_desc* fdesc_list;

	// free block list
	fcache_block_desc* fblock_list;
	unsigned int avail_blocks;

	// all fonts the system managed
	unsigned int total_fonts;
	avl_node_t* fonts_avltree;
	font_descriptor fonts[max_font_faces];

	// this must be at the end
	fcache_block blocks[1];

public:
	void initialize(void);

	// create a new font
	font_descriptor* load_font(const grphoal::uint128_t& fid);

	// find an exist font
	font_descriptor* find_font(const grphoal::uint128_t& fid);

	// create a new fcache
	fcache* load_font_cache(font_descriptor* fdesc, unsigned int fontsize);

	// find an exist fcache
	fcache* find_font_cache(font_descriptor* fdesc, unsigned int fontsize);

	// find an exist glyph
	agg::glyph_cache* find_glyph(fcache* fc, unsigned int glyph_code);

	// allocate a slot for glyph caching
	agg::glyph_cache* cache_glyph(fcache* fc, unsigned int glyph_code, 
		unsigned int data_size, unsigned int data_type,
		double advance_x, double advance_y);

private:
	font_descriptor* get_free_font_desc(void);
	fcache_block* get_free_font_block(void);
};

const static unsigned int cachebuf_total_blocks =
	(cachebuf_total_size - sizeof(fontcache))
	/ cachebuf_block_size + 1;

extern unsigned char fontcache_buffer[];

// get the font cache
fontcache* fntcache(void);
};

#endif // __CXX_GRPH_FONT_CACHE_H__
/* EOF */
